/**
 * Abbreviations:	ph = phone   num = number	frd = friend	fb = facebook	cmt = comment
 * 					sbcb = subscribe	pos = position	
 */
package com.activity;

import com.facebook.FbAuthorizeListener;
import com.facebook.FbLogoutListener;
import com.facebook.FbMgr;
import com.facebook.Util;
import com.misc.OnlineFrdView;
import com.misc.Tool;
import com.type.ByteArrayParcelable;
import com.type.Me;

import org.json.JSONArray;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.Toast;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.ArrayList;

public class MainActivity extends Activity implements FbAuthorizeListener, FbLogoutListener {
	// constant
//	static final String SERVER_IP = "10.4.81.21";	// set your server ip here
	static final String SERVER_IP = "192.168.1.100";
	static final String PORT = "9999";
	
	final int CHECK_ACCOUNT_INTERACT = 102;
	final int SEND_MY_FB_ID = 201;
	final int FETCH_ONLINE_FRIEND = 301;

	final int MENU_CREATE_ACTIVITIY = 1;
	final int MENU_RELATE_TO_ME_TOPIC_ACTIVITY= 2;
	final int MENU_SETTINGS = 3;

	public static final String MY_PH_NUM = "my_ph_num";
	public static final String MY_NAME = "my_name";
	public static final String MY_AVATAR= "my_avatar";
	public static final String FRD_PH_NUM = "frd_ph_num";
	
	final String MY_FB_USER_ID = "my_fb_user_id";
	final String FB_FRIENDS_ID_JSON_ARRAY = "fb_friends_id_json_array";
	
	// field
	OnlineFrdView onlineFrdView;
	ProgressDialog progressDialog;

	FbMgr fbMgr;
	SharedPreferences pref;
	Me me = new Me();
	
	static Socket socket;
	static DataOutputStream dos;
	static DataInputStream dis;

	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		
		fbMgr = new FbMgr(this);
		pref = PreferenceManager.getDefaultSharedPreferences(this);

		loadContactsFrd();
		loginQuery();
	}
	
	
	void loadContactsFrd() {
		Cursor cursorContacts = getContentResolver()
								.query(
									ContactsContract.Contacts.CONTENT_URI,
									null, null, null, null);
		while (cursorContacts.moveToNext()) {
			long contactId = cursorContacts.getLong(cursorContacts.getColumnIndex(BaseColumns._ID));
			Cursor cursorId = getContentResolver()
							  .query(
							      ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
							      null,
								  ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, 
								  null, null);
			if(cursorId.moveToFirst()) {
				String rawPhNum = cursorId.getString(cursorId.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
				me.getFrdPhNumList().add(rawPhNum.replaceAll("-", ""));
			}
		}
	}


	public void loginQuery() {
		final View dialogView = LayoutInflater.from(this).inflate(R.layout.login_query, null);
		(new AlertDialog.Builder(this).setTitle("Login").setView(dialogView)
				.setPositiveButton("OK", new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int whichButton) {
						String phNum = ((EditText) dialogView.findViewById(R.id.etLoginPhoneNumber)).getText().toString();
						String password = ((EditText) dialogView.findViewById(R.id.etLoginPassword)).getText().toString();
						if (TextUtils.isEmpty(phNum) || TextUtils.isEmpty(password)) 
							Toast.makeText(MainActivity.this, "empty field is not allowed", Toast.LENGTH_LONG);
						else {
							me.setPhNum(phNum);
							me.setPassword(password);
							(new CheckAccountTask(MainActivity.this)).execute(SERVER_IP, PORT, me.getPhNum(), me.getPassword());
						}
					}
				}).setNegativeButton("Register", new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						startActivityForResult(new Intent(MainActivity.this, RegisterActivity.class), 0);
					}
				}).setOnKeyListener(new DialogInterface.OnKeyListener() {
					@Override
					public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
						if(keyCode==KeyEvent.KEYCODE_BACK)
							finish();
						return false;
					}
				})).create().show();
	}
	
	
	class CheckAccountTask extends AsyncTask<String, Void, Me> {
	    MainActivity mainActivity;
	    String exceptionInfo = null;
	
	    public CheckAccountTask(MainActivity mainActivity) {
	        this.mainActivity = mainActivity;
	    }
	
	    @Override
		protected Me doInBackground(String... params) {
	    	Me dataPackage = new Me();
			try {
				socket = new Socket(params[0], Integer.parseInt(params[1]));
				dos = new DataOutputStream(socket.getOutputStream());
				dis = new DataInputStream(socket.getInputStream());
				dos.writeInt(CHECK_ACCOUNT_INTERACT);
				
				dos.writeUTF(params[2]);		// phone number
				if (dis.readBoolean()) {
					dos.writeUTF(params[3]);	// password
					if (dis.readBoolean()) {
						dataPackage.setName(dis.readUTF());
						dataPackage.setAvatar(new ByteArrayParcelable(Tool.receiveByteArray(dis)));
					} else
						exceptionInfo = "wrong password";
				} else
					exceptionInfo = "account does not exist, please register";
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					dis.close();
					dos.close();
					socket.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return dataPackage;
		}
	
	    @Override
	    protected void onPostExecute(Me dataPackage) {
	        if (mainActivity != null) {
	            mainActivity.onCheckAccountTaskComplete(dataPackage.getName(), dataPackage.getAvatar(), exceptionInfo);
	        }
	    }
	}

	
	public void onCheckAccountTaskComplete(String name, ByteArrayParcelable avatar, String exceptionInfo) {
		if(exceptionInfo == null) {
			me.setName(name);
			me.setAvatar(avatar);
			bindFbQuery();
		} else {
			Toast.makeText(this, exceptionInfo, Toast.LENGTH_LONG).show();
			loginQuery();
		}
	}
	
	
	public void bindFbQuery() {
		if (pref.getBoolean(me.getPhNum(), true)) {
			final View dialogView = LayoutInflater.from(this).inflate(R.layout.bind_fb_query, null);
			(new AlertDialog.Builder(this).setView(dialogView)
					.setTitle("Bind your FaceBook account?")
					.setPositiveButton("yes", new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int whichButton) {
							if(pref.getBoolean(me.getPhNum(), false))
								(new FetchOnlineFrdTask(MainActivity.this)).execute(new ParamForFetchOnlineFrdTask(SERVER_IP, Integer.parseInt(PORT), me.getFrdPhNumList(), pref));
							else
								fbMgr.fbAuthorize(MainActivity.this); // if authorize success, MainActivity.onFbAuthorizeComplete() will be called
						}
					}).setNeutralButton("not this time", new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							(new FetchOnlineFrdTask(MainActivity.this)).execute(new ParamForFetchOnlineFrdTask(SERVER_IP, Integer.parseInt(PORT), me.getFrdPhNumList(), pref));
						}
					}).setNegativeButton("never bind", new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							pref.edit().putBoolean(me.getPhNum(), false).commit();
							(new FetchOnlineFrdTask(MainActivity.this)).execute(new ParamForFetchOnlineFrdTask(SERVER_IP, Integer.parseInt(PORT), me.getFrdPhNumList(), pref));
						}
					}).setOnKeyListener(new DialogInterface.OnKeyListener() {
						@Override
						public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
							if(keyCode==KeyEvent.KEYCODE_BACK)
								finish();
							return false;
						}
					})).create().show();
		} else 
			(new FetchOnlineFrdTask(this)).execute(new ParamForFetchOnlineFrdTask(SERVER_IP, Integer.parseInt(PORT), me.getFrdPhNumList(), pref));
	}


	public void onFbAuthorizeComplete() {
		startProgressBar("", "Loading your facebook information, please wait.");
		
		try {
			String responseFrd = fbMgr.request("/me/friends");
			JSONArray jsonArray = Util.parseJson(responseFrd).getJSONArray("data");
			pref.edit().putString(FB_FRIENDS_ID_JSON_ARRAY, jsonArray.toString()).commit();
	
			String responseMe = fbMgr.request("/me");
			String myFbId = Util.parseJson(responseMe).getString("id");
			pref.edit().putString(MY_FB_USER_ID, myFbId).commit();
		} catch (Exception e) {
			e.printStackTrace();
		}
	
		/*
		 * we logout facebook, because facebook will remember my id and password and when next time authorize,
		 * it won't pop up the login input dialog, so we don't have opportunity to switch into another facebook
		 * account. if logout, the login input dialog will come out.
		 */
		fbMgr.fbLogout(this);	// if logout success, MainActivity.onFbLogoutComplete() will be called 	
	}


	void startProgressBar(String title, String message) {
		if (progressDialog == null)
			progressDialog = ProgressDialog.show(this, title, message);
		progressDialog.show();
	}


	@Override
	public void onFbLogoutComplete() {
		stopProgressBar();
		(new SendMyFbIdTask(MainActivity.this)).execute(SERVER_IP, PORT, me.getPhNum(), pref.getString(MY_FB_USER_ID, null));
	}


	void stopProgressBar() {
		if (progressDialog != null) {
			progressDialog.dismiss();
			progressDialog = null;
		}
	}


	class SendMyFbIdTask extends AsyncTask<String, Void, Void> {
	    MainActivity mainActivity;
	
	    public SendMyFbIdTask(MainActivity mainActivity) {
	        this.mainActivity = mainActivity;
	    }
	
	    @Override
		protected Void doInBackground(String... params) {
			try {
				socket = new Socket(params[0], Integer.parseInt(params[1]));
				dos = new DataOutputStream(socket.getOutputStream());
				dos.writeInt(SEND_MY_FB_ID);
				
				dos.writeUTF(params[2]);	// my phone number
				dos.writeUTF(params[3]);	// my facebook user id
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					dos.close();
					socket.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return null;
		}
	
	    @Override
	    protected void onPostExecute(Void result) {
	        if (mainActivity != null) {
	            mainActivity.onSendMyFbIdTaskComplete();
	        }
	    }
	}

	
	public void onSendMyFbIdTaskComplete() {
		pref.edit().putBoolean(me.getPhNum(), false).commit();
		(new FetchOnlineFrdTask(this)).execute(new ParamForFetchOnlineFrdTask(SERVER_IP, Integer.parseInt(PORT), me.getFrdPhNumList(), pref));
	}

	
	class ParamForFetchOnlineFrdTask {
		String serverIp;
		int port;
		ArrayList<String> frdPhNumList;
		SharedPreferences preference;
		public ParamForFetchOnlineFrdTask(String serverIp, int port, ArrayList<String> frdPhNumList, SharedPreferences preference) {
			this.serverIp = serverIp;
			this.port = port;
			this.frdPhNumList = frdPhNumList;
			this.preference = preference;
		}
		public String getServerIp() {
			return serverIp;
		}
		public int getPort() {
			return port;
		}
		public ArrayList<String> getFrdPhNumList() {
			return frdPhNumList;
		}
		public SharedPreferences getPreference() {
			return preference;
		}
	}
	class ResultForFetchOnlineFrdTask {
		ArrayList<String> phNumList = new ArrayList<String>();
		ArrayList<String> nameList = new ArrayList<String>();
		ArrayList<ByteArrayParcelable> avatarList = new ArrayList<ByteArrayParcelable>();
		public ArrayList<String> getPhNumList() {
			return phNumList;
		}
		public ArrayList<String> getNameList() {
			return nameList;
		}
		public ArrayList<ByteArrayParcelable> getAvatarList() {
			return avatarList;
		}
	}
	class FetchOnlineFrdTask extends AsyncTask<ParamForFetchOnlineFrdTask, Void, ResultForFetchOnlineFrdTask> {
	    MainActivity mainActivity;
	
	    public FetchOnlineFrdTask(MainActivity mainActivity) {
	        this.mainActivity = mainActivity;
	    }
	
	    @Override
		protected ResultForFetchOnlineFrdTask doInBackground(ParamForFetchOnlineFrdTask... params) {
	    	ResultForFetchOnlineFrdTask resultForFetchOnlineFrdTask = new ResultForFetchOnlineFrdTask();
			try {
				socket = new Socket(params[0].getServerIp(), params[0].getPort());
				dos = new DataOutputStream(socket.getOutputStream());
				dis = new DataInputStream(socket.getInputStream());
				dos.writeInt(FETCH_ONLINE_FRIEND);
				
				ArrayList<String> frdPhNumList = params[0].getFrdPhNumList();
				dos.writeInt(frdPhNumList.size());
				for(String frdPhNum : frdPhNumList) {
					dos.writeUTF(frdPhNum);
					if(dis.readBoolean()) {
						resultForFetchOnlineFrdTask.getPhNumList().add(dis.readUTF());
						resultForFetchOnlineFrdTask.getNameList().add(dis.readUTF());
						resultForFetchOnlineFrdTask.getAvatarList().add(new ByteArrayParcelable(Tool.receiveByteArray(dis)));
					}
				}
				
				String jsonArrayString = params[0].getPreference().getString(FB_FRIENDS_ID_JSON_ARRAY, null);
				if(jsonArrayString != null) { 
					dos.writeBoolean(true);
					JSONArray jsonArray = new JSONArray(jsonArrayString);
					int count = jsonArray.length(); 
					dos.writeInt(count);
					for(int i=0; i < count; i++) {
						try {
							dos.writeUTF(jsonArray.getJSONObject(i).getString("id"));
						} catch (Exception e) {
							e.printStackTrace();
						}
						if(dis.readBoolean()) {
							resultForFetchOnlineFrdTask.getPhNumList().add(dis.readUTF());
							resultForFetchOnlineFrdTask.getNameList().add(dis.readUTF() + "(facebook)");
							resultForFetchOnlineFrdTask.getAvatarList().add(new ByteArrayParcelable(Tool.receiveByteArray(dis)));
						}
					}
				} else 
					dos.writeBoolean(false);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					dis.close();
					dos.close();
					socket.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return resultForFetchOnlineFrdTask;
		}
	
	    @Override
	    protected void onPostExecute(ResultForFetchOnlineFrdTask resultForFetchOnlineFrdTask) {
	        if (mainActivity != null) {
	            mainActivity.onFetchOnlineFrdTaskComplete(resultForFetchOnlineFrdTask);
	        }
	    }
	}

	
	public void onFetchOnlineFrdTaskComplete(ResultForFetchOnlineFrdTask resultForFetchOnlineFrdTask) {
		onlineFrdView = new OnlineFrdView(this, me, resultForFetchOnlineFrdTask.getPhNumList(), resultForFetchOnlineFrdTask.getNameList(), resultForFetchOnlineFrdTask.getAvatarList());
		setContentView(onlineFrdView);
	}


	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if(requestCode==0) {
			if(resultCode==RESULT_OK) {
				me.setPhNum(data.getStringExtra(RegisterActivity.REGISTER_SUCCESS_PH_NUM));
				me.setName(data.getStringExtra(RegisterActivity.REGISTER_SUCCESS_NAME));
				me.setAvatar((ByteArrayParcelable) data.getParcelableExtra(RegisterActivity.REGISTER_SUCCESS_AVATAR));
				bindFbQuery();
			} else if(resultCode==RESULT_CANCELED) {
				loginQuery();
			}
		}
	}


	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		menu.add(Menu.NONE, MENU_CREATE_ACTIVITIY, Menu.NONE, "share a topic");
		menu.add(Menu.NONE, MENU_RELATE_TO_ME_TOPIC_ACTIVITY, Menu.NONE, "view topics related to me");
		menu.add(Menu.NONE, MENU_SETTINGS, Menu.NONE, "settings");
		return true;
	}


	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		Intent intent = new Intent();
		
		switch (item.getItemId()) {
		case MENU_CREATE_ACTIVITIY:
			intent.setClass(this, CreateTopicActivity.class);
			intent.putExtra(MY_PH_NUM, me.getPhNum());
			break;
		case MENU_RELATE_TO_ME_TOPIC_ACTIVITY:
			intent.setClass(this, RelateToMeTopicActivity.class);
			intent.putExtra(MY_PH_NUM, me.getPhNum());
			intent.putExtra(MY_NAME, me.getName());
			intent.putExtra(MY_AVATAR, me.getAvatar());
			break;
		case MENU_SETTINGS:
			intent.setClass(this, SettingActivity.class);
			intent.putExtra(MY_PH_NUM, me.getPhNum());
			break;
		default:
			break;
		}
	
		startActivity(intent);
		return super.onOptionsItemSelected(item);
	}


	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		onlineFrdView.prepareGridLayoutAxisArray(getResources().getConfiguration().orientation);
	}


	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if(keyCode==KeyEvent.KEYCODE_BACK) {
			if(onlineFrdView!=null && onlineFrdView.getIsOperateFrdLayerOn()) {
				onlineFrdView.setIsOperateFrdLayerOn(false);
				System.gc();
				setContentView(onlineFrdView);
				return true;
			} 
		}
		return super.onKeyDown(keyCode, event);
	}
}
